package com.geor.gcv.core.mat;

import java.util.ArrayList;
import java.util.List;

import org.opencv.core.Mat;

import com.geor.gcv.core.model.Area;
import com.geor.gcv.core.process.GrayProcess;
import com.geor.gcv.core.process.InputProcess;
import com.geor.gcv.core.process.ScreenShootProcess;
import com.geor.gcv.core.process.ThresholdProcess;
import com.geor.gcv.core.util.DataTool;

/**
 * 得到一个大区域的主要信息
 * 
 * @author geor.lusongnan
 *
 */
public class AreaBound {

	float scale = 1;

	private AreaBound() {
	}

	private AreaBound(float scale) {
		this.scale = scale;
	}

	public static AreaBound me() {
		return new AreaBound(1);
	}

	public static AreaBound me(float scale) {
		return new AreaBound(1 / scale);
	}

	public Area seek(Mat mat, Area area) {
		// 根据区域切Mat以及去除1px边框变为黑边
		if(mat.channels() != 1)
			mat = new GrayProcess(mat).process();
		
		Mat bin = new ThresholdProcess(new ScreenShootProcess(new InputProcess(mat), area), 21, 30).process();
		bin = Mats.clearBorder(bin);

		if (!doCheckArea(mat, area)) {
			return null;
		}

		// 得到横向字符行号
		List<Integer> rows = Mats.getRows(bin);

		if (rows.size() < 2) {
			return null;
		}
		// 过滤横向行号
		rows = filterRows(rows);

		// 得到纵向行号
		List<Integer> cols = Mats.getCols(bin, rows);
		// 过滤纵向行号
		cols = filterCols(cols);

		return new Area(area.getX() + cols.get(0), area.getY() + rows.get(0), cols.get(1) - cols.get(0),
				rows.get(1) - rows.get(0));
	}

	private List<Integer> filterCols(List<Integer> cols) {
		if (cols.size() <= 2) {
			return cols;
		}

		List<Integer> temps = new ArrayList<Integer>();

		int interval = (int) (7 / scale);

		int start = 0;
		for (int i = 1; i < cols.size(); i += 2) {
			int poor = cols.get(i) - cols.get(i - 1);
			if (poor > interval) {
				start = i - 1;
				break;
			}
		}
		int end = cols.size() - 1;
		for (int i = end; i > 0; i -= 2) {
			int poor = cols.get(i) - cols.get(i - 1);
			if (poor > interval) {
				end = i;
				break;
			}
		}

		temps.add(cols.get(start));
		temps.add(cols.get(end));

		return temps;
	}

	private List<Integer> filterRows(List<Integer> rows) {
		List<Integer> temps = new ArrayList<Integer>();
		for (int i = 1; i < rows.size(); i += 2) {
			temps.add(rows.get(i) - rows.get(i - 1));
		}

		List<Integer> lists = null;
		if (temps.size() <= 1) {
			lists = rows;
		} else {
			lists = new ArrayList<Integer>();
			int index = DataTool.getListMaxIndex(temps);
			lists.add(rows.get(index * 2));
			lists.add(rows.get(index * 2 + 1));
		}
		return lists;
	}

	private boolean doCheckArea(Mat mat, Area area) {
		int imgWidth = mat.cols();
		int imgHeight = mat.rows();

		int x = area.getX();
		int y = area.getY();
		int width = area.getWidth();
		int height = area.getHeight();

		if (x + width >= imgWidth) {
			return false;
		}

		if (y + height >= imgHeight) {
			return false;
		}

		return true;
	}

}
